package com.topfun.utils;

import org.joda.time.DateTime;
import org.joda.time.Interval;
import org.joda.time.Period;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by huandda on 2017-02-23.
 *
 * 日期工具类
 */
@SuppressWarnings({"unused", "WeakerAccess"})
public class DateUtil {
    // ===========================================================
    // Constants
    // ===========================================================


    // ===========================================================
    // Fields
    // ===========================================================


    // ===========================================================
    // Constructors
    // ===========================================================


    // ===========================================================
    // Getter &amp; Setter
    // ===========================================================


    // ===========================================================
    // Methods for/from SuperClass/Interfaces
    // ===========================================================


    // ===========================================================
    // Methods
    // ===========================================================

    private static final DateTimeFormatter SF_DateTime            = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
    private static final DateTimeFormatter SF_DateTimeMills       = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.SSS");
    private static final DateTimeFormatter SF_Date                = DateTimeFormat.forPattern("yyyy-MM-dd");
    private static final DateTimeFormatter SF_Month_CN            = DateTimeFormat.forPattern("yyyy年MM月");
    private static final DateTimeFormatter SF_Month               = DateTimeFormat.forPattern("yyyy-MM");
    private static final DateTimeFormatter SF_DateTimeNoSeparator = DateTimeFormat.forPattern("yyyyMMddHHmmss");
    // iso 8601
    private static final DateTimeFormatter SF_DateTime_iso8601    = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss'Z'");

    /**
     * 比较两个日期大小，日期格式需要yyyy-MM-dd格式
     *
     * @param pDateA 日期A
     * @param pDateB 日期B
     * @return 1 dateA < dataB; 0 dateA == dateB; -1 dateA > dateB
     */
    public static int compareDate(String pDateA, String pDateB) {
        if (!isDate(pDateA) || !isDate(pDateB)) {
            throw new RuntimeException("时间格式不正确，需要yyyy-MM-dd格式");
        }
        long tsA = getTimestamp(pDateA);
        long tsB = getTimestamp(pDateB);
        return tsA > tsB ? -1 : (tsA == tsB ? 0 : 1);
    }

    /**
     * 格式化日期
     * @param pDate 日期long
     * @param pFormat 格式化
     * @return 格式化日期字符串
     */
    public static String formatDate(long pDate, String pFormat){
        DateTimeFormatter formatter = DateTimeFormat.forPattern(pFormat);
        return  formatter.print(pDate);
    }
    /**
     * 获取时间字符串
     *
     * @return yyyyMMddHHmmss
     */
    public static String getDateTimeStringNoSeparator() {
        return SF_DateTimeNoSeparator.print(System.currentTimeMillis());
    }

    /**
     * 获取时间字符串
     *
     * @return yyyy-MM-dd HH:mm:ss
     */
    public static String getDateTimeStringISO8601() {
        return SF_DateTime_iso8601.print(System.currentTimeMillis());
    }

    /**
     * 获取时间字符串
     *
     * @return yyyy-MM-dd HH:mm:ss
     */
    public static String getDateTimeString() {
        return SF_DateTime.print(System.currentTimeMillis());
    }

    /**
     * 获取时间字符串
     *
     * @param pDate 时间对象
     * @return yyyy-MM-dd HH:mm:ss
     */
    public static String getDateTimeString(DateTime pDate) {
        return SF_DateTime.print(pDate);
    }

    /**
     * 获取时间字符串
     *
     * @param pTime 时间戳
     * @return yyyy-MM-dd HH:mm:ss
     */
    public static String getDateTimeString(Long pTime) {
        return SF_DateTime.print(pTime);
    }

    /**
     * 获取时间字符串
     *
     * @param pOffset 当前日期的偏移天数
     * @return yyyy-MM-dd HH:mm:ss
     */
    public static String getDateTimeString(int pOffset) {
        DateTime time = new DateTime();
        return SF_DateTime.print(time.plusDays(pOffset));
    }

    /**
     * 获取时间字符串
     *
     * @return yyyy-MM-dd
     */
    public static String getDateString() {
        return SF_Date.print(System.currentTimeMillis());
    }

    /**
     * 获取时间字符串
     *
     * @param pTime 时间戳
     * @return yyyy-MM-dd
     */
    public static String getDateString(Long pTime) {
        return SF_Date.print(pTime);
    }

    /**
     * 获取时间字符串
     *
     * @param pDate 时间对象
     * @return yyyy-MM-dd
     */
    public static String getDateString(DateTime pDate) {
        return SF_Date.print(pDate);
    }

    /**
     * 获取时间字符串
     *
     * @param pOffset 加减天数值
     * @return yyyy-MM-dd
     */
    public static String getDateString(int pOffset) {
        DateTime time = new DateTime();
        return SF_Date.print(time.plusDays(pOffset));
    }

    /**
     * 获取时间字符串
     * @param pTimestamp 时间戳
     * @return yyyy-MM-dd HH:mm:ss.SSS
     */
    public static String getDateTimeMills(long pTimestamp){
        return SF_DateTimeMills.print(pTimestamp);
    }

    /**
     * 获取月份字符串
     *
     * @return yyyy-MM
     */
    public static String getMonthString() {
        return SF_Month.print(System.currentTimeMillis());
    }

    /**
     * 获取月份字符串
     *
     * @return yyyy年MM月
     */
    public static String getMonthCNString() {
        return SF_Month_CN.print(System.currentTimeMillis());
    }

    /**
     * 获取月份字符串
     *
     * @param date 时间对象
     * @return yyyy年MM月
     */
    public static String getMonthCNString(DateTime date) {
        return SF_Month_CN.print(date);
    }

    /**
     * 获取月份字符串
     *
     * @param date 时间对象
     * @return yyyy-MM
     */
    public static String getMonthString(DateTime date) {
        return SF_Month.print(date);
    }

    /**
     * 获取月份字符串
     *
     * @param pOffset 月份偏移量
     * @return yyyy年MM月
     */
    public static String getMonthCNString(int pOffset) {
        DateTime time = new DateTime();
        return SF_Month_CN.print(time.plusMonths(pOffset).dayOfMonth().withMinimumValue());
    }

    /**
     * 获取月份字符串
     *
     * @param pOffset 月份偏移量
     * @return yyyy-MM
     */
    public static String getMonthString(int pOffset) {
        DateTime time = new DateTime();
        return SF_Month.print(time.plusMonths(pOffset).dayOfMonth().withMinimumValue());
    }

    /**
     * 获取月份第一天
     *
     * @param pOffset 月份偏移量
     * @return yyyy-MM-01
     */
    public static String getMonthStart(int pOffset) {
        DateTime time = new DateTime();
        return SF_Date.print(time.plusMonths(pOffset).dayOfMonth().withMinimumValue());
    }

    /**
     * 获取月份最后一天
     *
     * @param pOffset 月份偏移量
     * @return yyyy-MM-lastDay
     */
    public static String getMonthEnd(int pOffset) {
        DateTime time = new DateTime();
        return SF_Date.print(time.plusMonths(pOffset).dayOfMonth().withMaximumValue());
    }

    /**
     * 获取所给日期(yyyy-MM-dd)所属月份的第一天
     * 若所给参数不是合法日期，则返回当前月第一天
     *
     * @param pDate 给定日期
     * @param pDefaultOffset 月份偏移量
     *
     * @return yyyy-MM-01
     */
    public static String getMonthStart(String pDate, int pDefaultOffset) {
        if (isDate(pDate)) {
            try {
                DateTime time = SF_Date.parseDateTime(pDate);
                return SF_Date.print(time.dayOfMonth().withMinimumValue());
            } catch (Exception ignored) {
            }
        }
        return getMonthStart(pDefaultOffset);
    }

    /**
     * 获取所给日期(yyyy-MM-dd)所属月份的最后一天
     * 若所给参数不是合法日期，则返回当前月最后一天
     *
     * @param pDate 给定日期
     * @param pDefaultOffset 月份偏移量
     *
     * @return yyyy-MM-lastDay
     */
    public static String getMonthEnd(String pDate, int pDefaultOffset) {
        if (isDate(pDate)) {
            try {
                DateTime time = SF_Date.parseDateTime(pDate);
                return SF_Date.print(time.dayOfMonth().withMaximumValue());
            } catch (Exception ignored) {
            }
        }
        return getMonthEnd(pDefaultOffset);
    }

    /**
     * 增加天数
     *
     * @param pDate 指定日期(yyyy-MM-dd)
     * @param pDays     增减的天数
     *
     * @return yyyy-MM-dd
     */
    public static String addDate(String pDate, int pDays) {
        if (isDate(pDate)) {
            try {
                DateTime time = SF_Date.parseDateTime(pDate);
                return SF_Date.print(time.plusDays(pDays));
            } catch (Exception ignored) {
            }
        }
        return "";
    }

    /**
     * 增加月数
     *
     * @param pDate  指定日期(yyyy-MM-dd)
     * @param pMonth 增减的月数
     * @return yyyy-MM-dd
     */
    public static String addMonth(String pDate, int pMonth) {
        if (isDate(pDate)) {
            try {
                DateTime time = SF_Date.parseDateTime(pDate);
                return SF_Date.print(time.plusMonths(pMonth));
            } catch (Exception ignored) {
            }
        }
        return "";
    }

    /**
     * 判断字符串str是否为yyyy-MM-dd HH:mm:ss.SSS格式
     *
     * @param pString 日期字符串
     * @return 是否为yyyy-MM-dd HH:mm:ss.SSS格式
     */
    public static boolean isDateTimeMills(String pString) {
        boolean isDataTimeMills;
        try {
            SF_DateTimeMills.parseDateTime(pString);
            isDataTimeMills = true;
        } catch (Exception e) {
            isDataTimeMills = false;
        }
        return isDataTimeMills;
    }

    /**
     * 判断字符串str是否为yyyy-MM-dd HH:mm:ss格式
     *
     * @param pString 日期字符串
     * @return 是否为yyyy-MM-dd HH:mm:ss格式
     */
    public static boolean isDateTime(String pString) {
        boolean isDataTime;
        try {
            SF_DateTime.parseDateTime(pString);
            isDataTime = true;
        } catch (Exception e) {
            isDataTime = false;
        }
        return isDataTime;
    }

    /**
     * 判断字符串str是否为yyyy-MM-dd格式
     *
     * @param pString 日期字符串
     * @return 是否为yyyy-MM-dd格式
     */
    public static boolean isDate(String pString) {
        boolean isData;
        try {
            SF_Date.parseDateTime(pString);
            isData = true;
        } catch (Exception e) {
            isData = false;
        }
        return isData;
    }

    /**
     * 判断字符串str是否为HH格式
     *
     * @param pString 小时字符串
     * @return 是否为HH格式
     */
    public static boolean isHour(String pString) {
        Pattern pattern = Pattern.compile("^00|01|02|03|04|05|06|07|08|09|10|11|12|13|14|15|16|17|18|19|20|21|22|23$");
        Matcher matcher = pattern.matcher(pString);
        return matcher.matches();
    }

    /**
     * 获取当前时间字符串的时间戳
     *
     * @param pDateTime 日期字符串
     * @return 时间戳
     */
    public static long getTimestamp(String pDateTime) {
        if (isDateTime(pDateTime)) {
            try {
                DateTime time = SF_DateTime.parseDateTime(pDateTime);
                return time.getMillis();
            } catch (Exception ignored) {
            }
        } else if (isDate(pDateTime)) {
            try {
                DateTime time = SF_Date.parseDateTime(pDateTime);
                return time.getMillis();
            } catch (Exception ignored) {
            }
        }else if(isDateTimeMills(pDateTime)){
            try {
                DateTime time = SF_DateTimeMills.parseDateTime(pDateTime);
                return time.getMillis();
            } catch (Exception ignored) {
            }
        }
        return 0;
    }

    /**
     * 获取当前时间字符串的时间戳
     *
     * @param pDateTime iso8601时间字符串 yyyy-MM-ddTHH:mm:ssZ
     * @return 时间戳
     */
    public static long getTimestampISO8601(String pDateTime) {
        try {
            DateTime time = SF_DateTime_iso8601.parseDateTime(pDateTime);
            return time.getMillis();
        } catch (Exception ignored) {
        }
        return 0;
    }

    /**
     * 求两个时间天数差
     *
     * @param pBeginTime 开始时间 yyyy-MM-dd
     * @param pEndTime   结束时间 yyyy-MM-dd
     * @return 时间差 n
     */
    public static long daysBetween(String pBeginTime, String pEndTime) {
        Period period = new Interval(SF_Date.parseDateTime(pBeginTime), SF_Date.parseDateTime(pEndTime)).toPeriod();
        return period.getDays();
    }

    /**
     * 求两个时间天数差
     *
     * @param pBeginTime 开始时间 long
     * @param pEndTime   结束时间 long
     * @return 时间差 n
     */
    public static long daysBetween(long pBeginTime, long pEndTime) {
        Period period = new Interval(pBeginTime, pEndTime).toPeriod();
        return period.getDays();
    }

    /**
     * 将字符串转化为Date对象
     *
     * @param pDateTime 接受(yyyy-MM-dd HH:mm:ss)(yyyy-MM-dd)(yyyyMMddHHmmss)格式的字符串
     * @param pDefaultDate 默认值
     * @return Date对象
     */
    public static DateTime parseDateTime(String pDateTime, DateTime pDefaultDate) {
        try {
            return SF_DateTimeNoSeparator.parseDateTime(pDateTime);
        } catch (Exception e1) {
            try {
                return SF_DateTime.parseDateTime(pDateTime);
            } catch (Exception e2) {
                try {
                    return SF_Date.parseDateTime(pDateTime);
                } catch (Exception e3) {
                    return pDefaultDate;
                }
            }
        }
    }


    public static void main(String[] args){
    }

    // ===========================================================
    // Inner and Anonymous Classes
    // ===========================================================
}
